package com.intermancer.predictor.lifecycle;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.chain.impl.ChainBase;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;

import com.intermancer.predictor.breed.BreedStrategy;
import com.intermancer.predictor.breed.DefaultBreedStrategy;
import com.intermancer.predictor.feeder.Feeder;
import com.intermancer.predictor.inject.DefaultInjectStrategy;
import com.intermancer.predictor.inject.InjectStrategy;
import com.intermancer.predictor.mutation.DefaultMutationBreedStrategyWrapper;
import com.intermancer.predictor.select.DefaultSelectStrategy;
import com.intermancer.predictor.select.SelectStrategy;
import com.intermancer.predictor.store.StoreEntryDAO;

public class DefaultLifecycleDirectorFactory implements ObjectFactory, LifecycleDirectorFactory {
	
	private StoreEntryDAO storeEntryDAO;
	private Feeder feeder;
	private BreedStrategy breedStrategy;
	private SelectStrategy selectStrategy;
	private InjectStrategy injectStrategy;
	
	private Map<Class<? extends LifecycleCommand>, List<LifecycleListener>> listenerMap;
	
	public DefaultLifecycleDirectorFactory() {
		listenerMap = new HashMap<Class<? extends LifecycleCommand>, List<LifecycleListener>>();
	}
	
	public DefaultLifecycleDirectorFactory(StoreEntryDAO storeEntryDAO, Feeder feeder) {
		this();
		this.storeEntryDAO = storeEntryDAO;
		this.feeder = feeder;
	}

	@Override
	public LifecycleDirector getLifecycleDirector() {
		ChainBase chainBase = new ChainBase();
		chainBase.addCommand(getSelectCommand());
		chainBase.addCommand(getBreedCommand());
		chainBase.addCommand(getFeedCommand());
		chainBase.addCommand(getInjectCommand());
		
		LifecycleDirector lifecycleDirector = new LifecycleDirectorImpl(chainBase);
		return lifecycleDirector;
	}

	@Override
	public Object getObject() throws BeansException {
		return getLifecycleDirector();
	}

	private SelectCommand getSelectCommand() {
		if(selectStrategy == null) {
			selectStrategy = new DefaultSelectStrategy();
		}
		SelectCommand command = new SelectCommand(selectStrategy, storeEntryDAO);
		command.setLifecycleListeners(listenerMap.get(SelectCommand.class));
		return command;
	}
	
	private BreedCommand getBreedCommand() {
		if(breedStrategy == null) {
			breedStrategy = new DefaultBreedStrategy();
			breedStrategy = new DefaultMutationBreedStrategyWrapper(breedStrategy);
		}
		BreedCommand command = new BreedCommand(breedStrategy);
		command.setLifecycleListeners(listenerMap.get(BreedCommand.class));
		return command;
	}
	
	private FeedCommand getFeedCommand() {
		FeedCommand command = new FeedCommand(feeder, storeEntryDAO);
		command.setLifecycleListeners(listenerMap.get(FeedCommand.class));
		return command;
	}
	
	private InjectCommand getInjectCommand() {
		if(injectStrategy == null) {
			injectStrategy = new DefaultInjectStrategy();
		}
		InjectCommand command = new InjectCommand(injectStrategy, storeEntryDAO);
		command.setLifecycleListeners(listenerMap.get(InjectCommand.class));
		return command;
	}

	public void setStoreEntryDAO(StoreEntryDAO storeEntryDAO) {
		this.storeEntryDAO = storeEntryDAO;
	}

	public void setFeeder(Feeder feeder) {
		this.feeder = feeder;
	}

	public void setBreedStrategy(BreedStrategy breedStrategy) {
		this.breedStrategy = breedStrategy;
	}

	public void setSelectStrategy(SelectStrategy selectStrategy) {
		this.selectStrategy = selectStrategy;
	}

	public void setInjectStrategy(InjectStrategy injectStrategy) {
		this.injectStrategy = injectStrategy;
	}

	@Override
	public void addLifecycleListener(Class<? extends LifecycleCommand> clazz,
			LifecycleListener listener) {
		List<LifecycleListener> listeners = listenerMap.get(clazz);
		if (listeners == null) {
			listeners = new ArrayList<LifecycleListener>();
			listenerMap.put(clazz, listeners);
		}
		listeners.add(listener);
	}

}
